package com.iteaj.iot.serial;

import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.iteaj.iot.ConcurrentStorageManager;
import com.iteaj.iot.IotProtocolFactory;
import com.iteaj.iot.client.ClientComponent;
import com.iteaj.iot.client.ClientConnectProperties;
import com.iteaj.iot.client.IotClient;
import com.iteaj.iot.codec.filter.DecoderInterceptor;
import com.iteaj.iot.codec.filter.Interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.stream.Collectors;

public class SerialComponent extends ConcurrentStorageManager<String, IotClient> implements ClientComponent<SerialMessage> {

    private static final String NAME = "串口组件";
    private static final String DESC = "支持windows、mac、linux等串口通讯";

    private boolean start;
    private long startTime;
    private static SerialComponent serialComponent;
    private SerialConnectProperties connectProperties;
    private SerialEventProtocolHandle protocolHandle;
    private Logger logger = LoggerFactory.getLogger(getClass());

    protected SerialComponent() { }

    protected SerialComponent(SerialConnectProperties connectProperties) {
        this.connectProperties = connectProperties;
    }

    public static SerialComponent instance() {
        return instance(null);
    }

    public static SerialComponent instance(SerialConnectProperties connectProperties) {
        if(serialComponent == null) {
            serialComponent = new SerialComponent(connectProperties);
        }

        return serialComponent;
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public String getDesc() {
        return DESC;
    }

    @Override
    public boolean isStart() {
        return this.start;
    }

    @Override
    public long startTime() {
        return this.startTime;
    }

    @Override
    public void start(Object config) {
        this.startTime = System.currentTimeMillis();

        if(this.getConfig() != null) {
            SerialClient newClient = this.createNewClient(this.getConfig());
            newClient.init(null);
            newClient.connect();
        }
    }

    @Override
    public synchronized void close() {
        try {
            if(this.isStart()) {
                this.clients().forEach(item -> item.close());
            }
        } finally {
            this.start = false;
        }
    }

    @Override
    public IotProtocolFactory protocolFactory() {
        return null;
    }

    @Override
    public SerialConnectProperties getConfig() {
        return this.connectProperties;
    }

    @Override
    public SerialClient getClient() {
        if(this.getConfig() != null) {
            return this.getClient(getConfig());
        } else {
            return null;
        }
    }

    /**
     * 返回所有可用的端口
     * @return
     */
    public SerialPort[] available() {
        return SerialPort.getCommPorts();
    }

    @Override
    public synchronized void addClient(Object clientKey, IotClient value) {
        if(!this.isExists(clientKey.toString())) {
            this.add(clientKey.toString(), value);
        }
    }

    @Override
    public SerialClient getClient(Object clientKey) {
        return (SerialClient) this.get(clientKey.toString());
    }

    @Override
    public SerialClient removeClient(Object clientKey) {
        return (SerialClient) this.remove(clientKey.toString());
    }

    @Override
    public List<IotClient> clients() {
        return this.getStorage().values().stream().collect(Collectors.toList());
    }

    @Override
    public SerialClient createNewClient(ClientConnectProperties config) {
        IotClient client = this.getClient(config);
        if(client == null) {
            client = new SerialClient(this, (SerialConnectProperties) config);
        }

        return (SerialClient) client;
    }

    public SerialClient createNewClientAndConnect(ClientConnectProperties config) {
        IotClient client = this.getClient(config);
        if(client == null) {
            client = new SerialClient(this, (SerialConnectProperties) config);
        }

        client.init(null);
        client.connect();
        return (SerialClient) client;
    }

    public SerialClient createNewClientAndConnect(ClientConnectProperties config, SerialPortDataListener listener) {
        IotClient client = this.getClient(config);
        if(client == null) {
            client = new SerialClient(this, (SerialConnectProperties) config);
        }

        client.init(listener);
        client.connect();
        return (SerialClient) client;
    }

    public SerialEventProtocolHandle getProtocolHandle() {
        return protocolHandle;
    }

    public SerialComponent setProtocolHandle(SerialEventProtocolHandle protocolHandle) {
        this.protocolHandle = protocolHandle; return this;
    }

    @Override
    public void finished() {
        ClientComponent.super.finished();
        if(logger.isInfoEnabled()) {
            if(this.getConfig()== null) {
                logger.info("启用串口组件成功 - 简介: {}", getDesc());
            } else {
                logger.info("启用串口组件成功 - 默认串口: {} - 简介: {}", this.getConfig(), getDesc());
            }
        }
    }

    @Override
    public Interceptor getInterceptor() {
        return null;
    }
}
